package com.hmdp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.exception.WebException;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.hmdp.utils.RedisIdWorker;
import com.hmdp.utils.UserHolder;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

import static com.hmdp.utils.RedisConstants.SECKILL_ORDER_KEY;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@RequiredArgsConstructor
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {

    private final ISeckillVoucherService secondKillVoucherService;

    private final RedisIdWorker redisIdWorker;

    private final RedissonClient redissonClient;

    private final RedisTemplate<String, Object> redisTemplate;

    private final RabbitTemplate rabbitTemplate;

    private static final DefaultRedisScript<Long> SECKILL_SCRIPT;

    static {
        SECKILL_SCRIPT = new DefaultRedisScript<>();
        SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));
        SECKILL_SCRIPT.setResultType(Long.class);
    }

    @Override
    public Long seckillVoucher(Long voucherId) {
        // 查询优惠券
        SeckillVoucher voucher = secondKillVoucherService.getById(voucherId);

        // 判断优惠券的使用时间是否合理
        if (LocalDateTime.now().isBefore(voucher.getBeginTime())) {
            throw new WebException("秒杀券还未到使用时间！");
        }
        if (LocalDateTime.now().isAfter(voucher.getEndTime())) {
            throw new WebException("秒杀券已经过期！");
        }
        Long result = redisTemplate.execute(
                SECKILL_SCRIPT,
                Collections.emptyList(),
                voucherId,
                UserHolder.getUser().getId()
        );

        int r = result.intValue();
        if (r == 1) {
            throw new WebException("库存不足");
        }
        if (r == 2) {
            throw new WebException("请勿重复抢购");
        }

        if (r == 0) {
            VoucherOrder voucherOrder = new VoucherOrder();
            long orderId = redisIdWorker.nextId("order");
            voucherOrder.setId(orderId);
            voucherOrder.setUserId(UserHolder.getUser().getId());
            voucherOrder.setVoucherId(voucherId);
            rabbitTemplate.convertAndSend("seckill.exchange", "seckill.order", voucherOrder);
            return orderId;
        }

        return null;
    }

    //    @Override
//    public Long seckillVoucher(Long voucherId) {
//        // 查询优惠券
//        SeckillVoucher voucher = secondKillVoucherService.getById(voucherId);
//
//        // 判断优惠券的使用时间是否合理
//        if (LocalDateTime.now().isBefore(voucher.getBeginTime())) {
//            throw new MyException("秒杀券还未到使用时间！");
//        }
//        if (LocalDateTime.now().isAfter(voucher.getEndTime())) {
//            throw new MyException("秒杀券已经过期！");
//        }
//
//        // 判断库存是否充足
//        if (voucher.getStock() < 1) {
//            throw new MyException("库存不足");
//        }
//
//        // 获取代理对象
//        IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
//        return proxy.createVoucherOrder(voucherId);
//    }
//
    @Transactional
    public Long createVoucherOrder(Long voucherId) {
        RLock lock = redissonClient.getLock(SECKILL_ORDER_KEY + UserHolder.getUser().getId());
//        boolean isLocked = false;
        try {
            boolean isLocked = lock.tryLock(0, 10, TimeUnit.SECONDS);
            if (!isLocked) {
                throw new WebException("服务器异常，请稍后重试");
            }

            // 防止用户重复下单
            LambdaQueryWrapper<VoucherOrder> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(VoucherOrder::getUserId, UserHolder.getUser().getId())
                    .eq(VoucherOrder::getVoucherId, voucherId);
            VoucherOrder isRepeat = super.getOne(queryWrapper);
            if (isRepeat != null) {
                throw new WebException("请勿重复抢购！");
            }

            // 判断库存是否充足以及扣减库存
            LambdaUpdateWrapper<SeckillVoucher> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(SeckillVoucher::getVoucherId, voucherId)
                    .gt(SeckillVoucher::getStock, 0)
                    .setSql("stock = stock - 1");
            long count = secondKillVoucherService.getBaseMapper().update(null, updateWrapper);
            if (count == 0) {
                // 扣减失败
                throw new WebException("库存不足");
            }

            // 创建订单
            VoucherOrder voucherOrder = new VoucherOrder();
            voucherOrder.setId(redisIdWorker.nextId("order"));
            voucherOrder.setUserId(UserHolder.getUser().getId());
            voucherOrder.setVoucherId(voucherId);
            super.save(voucherOrder);
            return voucherOrder.getId();
        } catch (Exception e) {
            throw new WebException("服务器繁忙");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }


//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public Long seckillVoucher(Long voucherId) {
//        // 查询优惠券
//        SeckillVoucher voucher = secondKillVoucherService.getById(voucherId);
//
//        // 判断优惠券的使用时间是否合理
//        if (LocalDateTime.now().isBefore(voucher.getBeginTime())) {
//            throw new MyException("秒杀券还未到使用时间！");
//        }
//        if (LocalDateTime.now().isAfter(voucher.getEndTime())) {
//            throw new MyException("秒杀券已经过期！");
//        }
//
//        // 判断库存是否充足
//        if (voucher.getStock() < 1) {
//            throw new MyException("库存不足");
//        }
//
//        RLock lock = redissonClient.getLock(SECKILL_STOCK_KEY + UserHolder.getUser().getId());
//        boolean isLocked = false;
//        try {
//            isLocked = lock.tryLock(5, 10, TimeUnit.SECONDS);
//            if (!isLocked) {
//                throw new MyException("服务器异常，请稍后重试");
//            }
//
//            // 防止用户重复下单
//            LambdaQueryWrapper<VoucherOrder> queryWrapper = new LambdaQueryWrapper<>();
//            queryWrapper.eq(VoucherOrder::getUserId, UserHolder.getUser().getId())
//                    .eq(VoucherOrder::getVoucherId, voucherId);
//            VoucherOrder isRepeat = super.getOne(queryWrapper);
//            if (isRepeat != null) {
//                throw new MyException("请勿重复抢购！");
//            }
//
//            // 判断库存是否充足以及扣减库存
//            LambdaUpdateWrapper<SeckillVoucher> updateWrapper = new LambdaUpdateWrapper<>();
//            updateWrapper.eq(SeckillVoucher::getVoucherId, voucherId)
//                    .gt(SeckillVoucher::getStock, 0)
//                    .setSql("stock = stock - 1");
//            long count = secondKillVoucherService.getBaseMapper().update(null, updateWrapper);
//            if (count == 0) {
//                // 扣减失败
//                throw new MyException("库存不足");
//            }
//
//            // 创建订单
//            VoucherOrder voucherOrder = new VoucherOrder();
//            voucherOrder.setId(redisIdWorker.nextId("order"));
//            voucherOrder.setUserId(UserHolder.getUser().getId());
//            voucherOrder.setVoucherId(voucherId);
//            super.save(voucherOrder);
//
//            return voucherOrder.getId();
//
//        } catch (Exception e) {
//            throw new MyException("服务器繁忙");
//        } finally {
//            if (isLocked) {
//                lock.unlock();
//            }
//        }
//    }
//
//
//    @Override
//    public Long createVoucherOrder(Long voucherId) {
//        return 1L;
//    }
}
